package com.vertx.core.beam;

import com.vertx.core.annotation.base.AnnotationExplain;
import com.vertx.core.annotation.base.ClassAnnotationExplain;
import com.vertx.core.annotation.base.FieldAnnotationExplain;
import com.vertx.core.annotation.data.explain.QueryAnnotationExplain;
import com.vertx.core.annotation.inject.explain.AutowiredExplain;
import com.vertx.core.annotation.inject.explain.ComponentExplain;
import com.vertx.web.explain.RestExplain;
import io.vertx.core.Vertx;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 描述:抽象beam工厂类
 * 创建人:hzw
 * 创建时间: 2018/4/17 15:57
 **/
public abstract class AbstractBeanFactory implements BeanFactory{

    //存放所有bean的线程安全的map
    protected ConcurrentHashMap<String, BeanContainer> beans = new ConcurrentHashMap<String, BeanContainer>();

    //加载注解解释器列表
    protected ConcurrentHashMap<Class, AnnotationExplain> annotationExplainContainer = new ConcurrentHashMap<>();

    //已经注册的bean列表
    private ConcurrentHashMap<Class, String> registerBeanClassMap = new ConcurrentHashMap<>();

    private String[] scanPackage;

    public AbstractBeanFactory(String[] scanPackage) {
        this.scanPackage=scanPackage;
        loadDefaultAnnotationExplain();
    }

    public void initialize() throws Exception {
        for (Map.Entry<String, BeanContainer> bean : beans.entrySet()) {
            getBean(bean.getKey());
        }
    }

    public Object getBean(String beanName) throws Exception {
        if (beanName != null && beanName.length() > 0 && beans.containsKey(beanName)) {
            BeanContainer beanContainer = beans.get(beanName);
            Object bean = beanContainer.getBean();
            if (bean == null) {
                bean = beanContainer.getBeanClass().newInstance();
                beanContainer.setBean(bean);
                setProperty(beanContainer);
                setMethod(beanContainer);
            }
            return bean;
        }
        return null;
    }

    public Object getBean(Class classes) {
        if (assertExistBean(classes)) {
            try {
                return getBean(registerBeanClassMap.get(classes));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }


    //根据class创建相应的bean
    public void setClass(Class classes,Vertx vertx) throws Exception {
        //不是抽象类和接口才进行注册
        if (!classes.isInterface() && !Modifier.isAbstract(classes.getModifiers())) {
            for (Annotation annotation : classes.getAnnotations()) {
                if (annotationExplainContainer.containsKey(annotation.annotationType())) {
                    ClassAnnotationExplain explain = (ClassAnnotationExplain) annotationExplainContainer.get(annotation.annotationType());
                    explain.handler(classes, annotation, this,new Object[]{vertx});
                }
            }
        }

    }
    //设置方法
    protected abstract void setMethod(BeanContainer beanContainer) throws Exception;


    private void setProperty(BeanContainer beanContainer) throws Exception {
        //获取所有字段(私有公有)
        Field[] fields = beanContainer.getBeanClass().getDeclaredFields();
        for (Field field : fields) {
            for (Annotation annotation : field.getAnnotations()) {
                if (annotationExplainContainer.containsKey(annotation.annotationType())) {
                    FieldAnnotationExplain explain = (FieldAnnotationExplain) annotationExplainContainer.get(annotation.annotationType());
                    explain.handler(beanContainer, field, annotation, this, new Object[]{scanPackage});
                }
            }
        }
    }

    public String getSimpleClassName(Class classes) {
        String tmp = classes.getName().substring(classes.getName().lastIndexOf(".") + 1);
        String firstChar = tmp.substring(0, 1);
        return firstChar.toLowerCase() + tmp.substring(1, tmp.length());
    }

    //注册bean
    public void registerBean(String beanName, BeanContainer beanContainer) throws Exception {
        if (beanName != null && beanContainer != null && beanContainer.getBeanClass() != null) {
            beans.put(beanName, beanContainer);
            registerBeanClassMap.put(beanContainer.getBeanClass(), beanName);
        }
    }


    public int getBeanCount() {
        return beans.size();
    }

    public boolean assertExistBean(Class classes) {
        if (registerBeanClassMap.containsKey(classes)) {
            return true;
        }
        return false;
    }

    public void registerAnnotationExplain(Class classes) throws Exception {
        //如果类是AnnotationExplain接口的实现，且不是一个接口和抽象类就放入解释器容器
        if (AnnotationExplain.class.isAssignableFrom(classes) &&
               !classes.isInterface() && !Modifier.isAbstract(classes.getModifiers())) {
            AnnotationExplain explain = (AnnotationExplain) classes.newInstance();
            //允许后一个覆盖前一个
//                if (annotationExplainContainer.contains(explain.getExplainClass())){
//                    throw new AnnotationExplainAlreadyExistedException(
//                            explain.getExplainClass().annotationType().getName()+"注解的解释器已经存在");
//                }
            annotationExplainContainer.put(explain.getExplainClass().annotationType(), explain);
        }
    }


    //读取框架自身的注解解释器
    private void loadDefaultAnnotationExplain() {
        try {
            registerAnnotationExplain(RestExplain.class);
            registerAnnotationExplain(ComponentExplain.class);
            registerAnnotationExplain(QueryAnnotationExplain.class);
            registerAnnotationExplain(AutowiredExplain.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public ConcurrentHashMap<Class, AnnotationExplain> getAnnotationExplainContainer() {
        return annotationExplainContainer;
    }

}
